home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / in_utils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-16  |  15.8 KB  |  593 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: in_utils.c,v 5.11 1993/05/16 20:56:18 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.11 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: in_utils.c,v $
  17.  * Revision 5.11  1993/05/16  20:56:18  syd
  18.  * fix want-to patch collision
  19.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  20.  *
  21.  * Revision 5.10  1993/05/08  20:25:33  syd
  22.  * Add sleepmsg to control transient message delays
  23.  * From: Syd
  24.  *
  25.  * Revision 5.9  1993/04/12  03:38:19  syd
  26.  * In GetPrompt(), when timeout = 0 make sure we check the return of
  27.  * ReadCh() for EINTR on non-POSIX (BSDish) systems.
  28.  * From: tom@osf.org
  29.  *
  30.  * Revision 5.8  1993/04/12  03:09:17  syd
  31.  * want_to() wrote "No." when user pressed return even if the default answer
  32.  * wasn't == *def_ans_no.
  33.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  34.  *
  35.  * Revision 5.7  1993/04/12  02:34:36  syd
  36.  * I have now added a parameter which controls whether want_to clears the
  37.  * line and centers the question or behaves like it did before. I also
  38.  * added a 0 at the end of the parameter list to all the other calls to
  39.  * want_to where a centered question on a clean line is not desirable.
  40.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  41.  *
  42.  * Revision 5.6  1993/01/30  15:57:19  syd
  43.  * fix where it clears the prompt from
  44.  *
  45.  * Revision 5.5  1993/01/29  03:43:46  syd
  46.  * back out change to clear question line,
  47.  * its worse that the original problem.
  48.  * From: Syd
  49.  *
  50.  * Revision 5.4  1993/01/27  20:48:01  syd
  51.  * Change where confirm prompt are written.
  52.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  53.  *
  54.  * Revision 5.3  1992/12/24  21:42:01  syd
  55.  * Fix messages and nls messages to match.  Plus use want_to
  56.  * where appropriate.
  57.  * From: Syd, via prompting from Jan Djarv <Jan.Djarv@sa.erisoft.se>
  58.  *
  59.  * Revision 5.2  1992/11/15  01:15:28  syd
  60.  * The alias message_count isn't set to zero if the last alias has
  61.  * been deleted from the alias table. As no aliases are reread from
  62.  * the aliases database the message_count is left as it was before.
  63.  *
  64.  * Fixed that the function do_newalias() sometimes returns without freeing
  65.  * the buffer allocated before. The patch adds these free calls.
  66.  *
  67.  * When you erroneously type a number in your folder elm asks you for
  68.  * a new current message number. But now if you erase this one number
  69.  * and leave the string empty elm will set the new current message to
  70.  * the second message on our sun4! The patch adds a check for an empty
  71.  * string and returns the current number if no number was entered.
  72.  * From: vogt@isa.de (Gerald Vogt)
  73.  *
  74.  * Revision 5.1  1992/10/03  22:58:40  syd
  75.  * Initial checkin as of 2.4 Release at PL0
  76.  *
  77.  *
  78.  ******************************************************************************/
  79.  
  80. /** Mindless I/O routines for ELM 
  81.     
  82. **/
  83.  
  84. #include "headers.h"
  85. #include "s_elm.h"
  86. #include <errno.h>
  87. #include <ctype.h>
  88.  
  89. #ifdef BSD
  90. #  undef tolower
  91. #endif
  92.  
  93. extern int errno;        /* system error number */
  94.  
  95. unsigned alarm();
  96.  
  97. #define isstopchar(c)        (c == ' ' || c == '\t' || c == '/')
  98. #define isslash(c)        (c == '/')
  99. #define erase_a_char()        { Writechar(BACKSPACE); Writechar(' '); \
  100.                       Writechar(BACKSPACE); fflush(stdout); }
  101.  
  102. int
  103. want_to(question, dflt, where, clear_and_center)
  104. char *question, dflt;
  105. int where, clear_and_center;
  106. {
  107.     /** Ask 'question' on 'where' left enough to just leave room for an
  108.         answer, returning the answer in lower case.
  109.         Echo answer as full "Yes" or "No".  'dflt' is the 
  110.         default answer if <return> is pressed. (Note: 'dflt' is also what 
  111.         will be returned if <return> is pressed!)
  112.     **/
  113.     register int ch, cols;
  114.  
  115.     cols = COLUMNS - (strlen(question) + 5 );    /* 5 for "Yes." + 1 */
  116.     if (cols < 0) {
  117.         cols = 0;
  118.     }
  119.  
  120.     MoveCursor(where, (clear_and_center || (cols < 2)) ? 0 : cols-2);
  121.     CleartoEOLN();
  122.  
  123.     PutLine3(where, clear_and_center ? cols/2 : cols,
  124.          "%s%c%c", question, dflt, BACKSPACE);
  125.     fflush(stdout);
  126.     fflush(stdin);
  127.  
  128.     ch = ReadCh();
  129.     ch = tolower(ch);
  130.  
  131.     while (!( ch == *def_ans_yes || ch == *def_ans_no || ch == '\n' || ch == '\r')) {
  132.       ch = ReadCh();
  133.       ch = tolower(ch);
  134.     }
  135.     if(ch == '\n' || ch == '\r')
  136.       ch = dflt;
  137.  
  138.     if(ch == *def_ans_yes)
  139.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmYesWord, "Yes."), 0);
  140.     else if (ch == *def_ans_no)
  141.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoWord, "No."), 0);
  142.     else
  143.       return(ch); /* Don't write anything, just return */
  144.  
  145.     if (sleepmsg > 0)
  146.         sleep((sleepmsg + 1) / 2);
  147.     MoveCursor(where, (clear_and_center || (cols < 2)) ? 0 : cols-2);
  148.     CleartoEOLN();
  149.  
  150.     return(ch);
  151. }
  152.  
  153. int
  154. read_number(ch, item)
  155. char ch, *item;
  156. {
  157.     /** Read a number, where 'ch' is the leading digit! **/
  158.     
  159.     char buff[NLEN];
  160.     int  num;
  161.  
  162.     buff[0] = ch;
  163.     buff[1] = '\0';
  164.  
  165.     PutLine1(LINES-3, COLUMNS-40,catgets(elm_msg_cat, ElmSet, ElmSetCurrentTo,
  166.         "Set current %s to :"), item);
  167.     if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1)
  168.       return(current);
  169.  
  170.     if (buff[0] == '\0')
  171.       return(current);
  172.  
  173.     sscanf(buff,"%d", &num);
  174.     return(num);
  175. }
  176.  
  177. int
  178. optionally_enter(string, x, y, append_current, passwd)
  179. char *string;
  180. int  x,y, append_current, passwd;
  181. {
  182.     /** This will display the string on the screen and allow the user to
  183.         either accept it (by pressing RETURN) or alter it according to
  184.         what the user types.   The various flags are:
  185.              string    is the buffer to use (with optional initial value)
  186.           x,y       is the location we're at on the screen (-1,-1 means
  187.                that we can't use this info and need to find out
  188.                the current location)
  189.          append_current  means that we have an initial string and that
  190.                the cursor should be placed at the END of the line,
  191.                not the beginning (the default).
  192.          passwd       accept non-printing characters and do not echo
  193.                entered characters.
  194.           
  195.         If we hit an interrupt or EOF we'll return non-zero.
  196.     **/
  197.  
  198.     int ch;
  199.     register int ch_count = 0, iindex = 0, escaped = OFF;
  200.     register int len = strlen(string), maxbuf = SLEN;
  201.  
  202.     clearerr(stdin);
  203.  
  204.     if(!passwd) {
  205.       if(!(x >=0 && y >= 0))
  206.         GetXYLocation(&x, &y);
  207.       PutLine1(x, y, "%s", string);    
  208.     }
  209.  
  210.     CleartoEOLN();
  211.  
  212.     if ( len > maxbuf ) {
  213.       maxbuf = len;
  214.     }
  215.  
  216.     if (! append_current) {
  217.       MoveCursor(x,y);
  218.     }
  219.     else
  220.       iindex = strlen(string);
  221.  
  222.     if (cursor_control)
  223.       transmit_functions(OFF);
  224.  
  225.     /** now we have the screen as we want it and the cursor in the 
  226.         right place, we can loop around on the input and return the
  227.         string as soon as the user presses <RETURN>
  228.     **/
  229.  
  230.     do {
  231.       ch = getchar();
  232.  
  233.       if (ch == ctrl('D') || ch == EOF) {        /* we've hit EOF */
  234.         if (cursor_control)
  235.           transmit_functions(ON);
  236.         return(1);
  237.       }
  238.  
  239.       if (ch_count++ == 0) {
  240.         if (ch == '\n' || ch == '\r') {
  241.           if (cursor_control)
  242.             transmit_functions(ON);
  243.           return(0);
  244.         }
  245.         else if (! append_current) {
  246.           CleartoEOLN();
  247.           iindex = (append_current? strlen(string) : 0);
  248.         }
  249.       }
  250.  
  251.       /* the following is converted from a case statement to
  252.          allow the variable characters (backspace, kill_line
  253.          and break) to be processed.  Case statements in
  254.          C require constants as labels, so it failed ...
  255.       */
  256.  
  257.       if (ch == backspace &&
  258.         (!escaped || (!isprint(ch) && !passwd))) {
  259.         /* This is tricky. Here we are dealing with all situations
  260.          * under which a backspace (really whatever erase char is
  261.          * set to, not necessarily \b) erases the previous character.
  262.          * It will erase unless escaped, because if it's escaped
  263.          * it is taken literally. There is one exception to that --
  264.          * if backspace would be rejected (we don't accept non-printing
  265.          * characters in non-passwd mode), we accept it here as an
  266.          * erasing character, for it if got rejected there would
  267.          * be no way of erasing a preceding backslash. */
  268.         escaped = OFF;
  269.         if (iindex > 0) {
  270.           if(!passwd)
  271.         Writechar(BACKSPACE);
  272.             iindex--;
  273.         }
  274.         if(!passwd) {
  275.           Writechar(' ');
  276.           Writechar(BACKSPACE);
  277.           fflush(stdout);
  278.         }
  279.       }
  280.       else if (ch == EOF || ch == '\n' || ch == '\r') {
  281.         escaped = OFF;
  282.         string[iindex] = '\0';
  283.         if (cursor_control)
  284.           transmit_functions(ON);
  285.         return(0);
  286.       }
  287.       else if (!passwd && ch == ctrl('W')) {    /* back up a word! */
  288.         escaped = OFF;
  289.         if (iindex == 0)
  290.           continue;        /* no point staying here.. */
  291.         iindex--;
  292.         if (isslash(string[iindex])) {
  293.           erase_a_char();
  294.         }
  295.         else {
  296.           while (iindex >= 0 && isspace(string[iindex])) {
  297.             iindex--;
  298.             erase_a_char();
  299.           }
  300.  
  301.           while (iindex >= 0 && ! isstopchar(string[iindex])) {
  302.             iindex--;
  303.             erase_a_char();
  304.           }
  305.           iindex++;    /* and make sure we point at the first AVAILABLE slot */
  306.         }
  307.       }
  308.       else if (!passwd && ch == ctrl('R')) {
  309.         escaped = OFF;
  310.         string[iindex] = '\0';
  311.         PutLine1(x,y, "%s", string);    
  312.         CleartoEOLN();
  313.       }
  314.       else if (!escaped && ch == kill_line) {
  315.         /* needed to test if escaped since kill_line character could
  316.          * be a desired valid printing character */
  317.         escaped = OFF;
  318.         if(!passwd) {
  319.           MoveCursor(x,y);
  320.           CleartoEOLN();
  321.         }
  322.         iindex = 0;
  323.       }
  324.       else if (ch == '\0') {
  325.         escaped = OFF;
  326.         if (cursor_control)
  327.           transmit_functions(ON);
  328.         fflush(stdin);     /* remove extraneous chars, if any */
  329.         string[0] = '\0'; /* clean up string, and... */
  330.         return(-1);
  331.       }
  332.       else if (!passwd && !isprint(ch)) {
  333.         /* non-printing character - warn with bell*/
  334.         /* don't turn off escaping backslash since current character
  335.          * doesn't "use it up".
  336.          */
  337.         Writechar('\007');
  338.       }
  339.       else {  /* default case */
  340.           if(escaped && (ch == backspace || ch == kill_line)) {
  341.         /* if last character was a backslash,
  342.          * and if this character is escapable
  343.          * simply write this character over it even if
  344.          * this character is a backslash.
  345.          */
  346.         if(!passwd)
  347.           Writechar(BACKSPACE);
  348.         iindex--;
  349.         string[iindex++] = ch;
  350.         if(!passwd)
  351.           Writechar(ch);
  352.             escaped = OFF;
  353.           } else {
  354.         string[iindex++] = ch;
  355.         if(!passwd)
  356.           Writechar(ch);
  357.         escaped = ( ch == '\\' ? ON : OFF);
  358.           }
  359.       }
  360.     } while (iindex < maxbuf);
  361.  
  362.     string[iindex] = '\0';
  363.  
  364.     if (cursor_control)
  365.       transmit_functions(ON);
  366.  
  367.     return(0);
  368. }
  369.  
  370. int
  371. pattern_enter(string, alt_string, x, y, alternate_prompt)
  372. char *string, *alt_string, *alternate_prompt;
  373. int  x,y;
  374. {
  375.     /** This function is functionally similar to the routine
  376.         optionally-enter, but if the first character pressed
  377.         is a '/' character, then the alternate prompt and string
  378.         are used rather than the normal one.  This routine 
  379.         returns 1 if alternate was used, 0 if not
  380.     **/
  381.  
  382.     int ch;
  383.     register int iindex = 0, escaped = OFF;
  384.  
  385.     PutLine1(x, y, "%s", string);    
  386.     CleartoEOLN();
  387.     MoveCursor(x,y);
  388.  
  389.     if (cursor_control)
  390.       transmit_functions(OFF);
  391.  
  392.     ch = getchar();
  393.  
  394.     if (ch == '\n' || ch == '\r') {
  395.       if (cursor_control)
  396.         transmit_functions(ON);
  397.       return(0);    /* we're done.  No change needed */
  398.     }
  399.     
  400.     if (ch == '/') {
  401.       PutLine1(x, 0, "%s", alternate_prompt);
  402.       CleartoEOLN();
  403.       (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
  404.          FALSE, FALSE);
  405.       return(1);
  406.     }
  407.  
  408.     CleartoEOLN();
  409.  
  410.     iindex = 0;
  411.  
  412.     if (ch == kill_line) {
  413.       MoveCursor(x,y);
  414.           CleartoEOLN();
  415.       iindex = 0;
  416.     }
  417.     else if (ch != backspace) {
  418.       if(ch == '\\') escaped = ON;
  419.       Writechar(ch);
  420.       string[iindex++] = ch;
  421.     }
  422.     else if (iindex > 0) {
  423.       iindex--;
  424.       erase_a_char();
  425.     }
  426.     else {
  427.       Writechar(' ');
  428.       Writechar(BACKSPACE);
  429.     }
  430.  
  431.     do {
  432.       fflush(stdout);
  433.       ch = getchar();
  434.  
  435.       /* the following is converted from a case statement to
  436.          allow the variable characters (backspace, kill_line
  437.          and break) to be processed.  Case statements in
  438.          C require constants as labels, so it failed ...
  439.       */
  440.  
  441.         if (ch == backspace &&
  442.           (!escaped || !isprint(ch)) ) {
  443.           /* This is tricky. Here we are dealing with all situations
  444.            * under which a backspace (really whatever erase char is
  445.            * set to, not necessarily \b) erases the previous character.
  446.            * It will erase unless escaped, because if it's escaped
  447.            * it is taken literally. There is one exception to that --
  448.            * if backspace would be rejected (we don't accept non-printing
  449.            * characters in non-passwd mode), we accept it here as an
  450.            * erasing character, for it if got rejected there would
  451.            * be no way of erasing a preceding backslash. */
  452.           escaped = OFF;
  453.               if (iindex > 0) {
  454.         iindex--;
  455.         erase_a_char();
  456.           }
  457.           else {
  458.         Writechar(' ');
  459.         Writechar(BACKSPACE);
  460.           }
  461.         }
  462.         else if (ch == '\n' || ch == '\r') {
  463.           escaped = OFF;
  464.           string[iindex] = '\0';
  465.           if (cursor_control)
  466.             transmit_functions(ON);
  467.           return(0);
  468.         }
  469.         else if (ch == ctrl('W')) {
  470.           escaped = OFF;
  471.           if (iindex == 0)
  472.             continue;        /* no point staying here.. */
  473.           iindex--;
  474.           if (isslash(string[iindex])) {
  475.             erase_a_char();
  476.           }
  477.           else {
  478.             while (iindex >= 0 && isspace(string[iindex])) {
  479.               iindex--;
  480.               erase_a_char();
  481.             }
  482.  
  483.             while (iindex >= 0 && ! isstopchar(string[iindex])) {
  484.               iindex--;
  485.               erase_a_char();
  486.             }
  487.             iindex++;/* and make sure we point at the first AVAILABLE slot */
  488.           }
  489.         }
  490.         else if (ch == ctrl('R')) {
  491.           escaped = OFF;
  492.           string[iindex] = '\0';
  493.           PutLine1(x,y, "%s", string);    
  494.           CleartoEOLN();
  495.         }
  496.         else if (!escaped && ch == kill_line) {
  497.           /* needed to test if escaped since kill_line character could
  498.            * be a desired valid printing character */
  499.           escaped = OFF;
  500.           MoveCursor(x,y);
  501.               CleartoEOLN();
  502.           iindex = 0;
  503.         }
  504.         else if (ch == '\0') {
  505.           escaped = OFF;
  506.           if (cursor_control)
  507.             transmit_functions(ON);
  508.           fflush(stdin);     /* remove extraneous chars, if any */
  509.           string[0] = '\0'; /* clean up string, and... */
  510.           return(-1);
  511.         }
  512.         else if (!isprint(ch)) {
  513.           /* non-printing character - warn with bell*/
  514.           /* don't turn off escaping backslash since current character
  515.            * doesn't "use it up".
  516.            */
  517.           Writechar('\007');
  518.         }
  519.         else {  /* default case */
  520.         if(escaped && (ch == backspace || ch == kill_line)) {
  521.           /* if last character was a backslash,
  522.            * and if this character is escapable
  523.            * simply write this character over it even if
  524.            * this character is a backslash.
  525.            */
  526.           Writechar(BACKSPACE);
  527.           iindex--;
  528.           string[iindex++] = ch;
  529.           Writechar(ch);
  530.           escaped = OFF;
  531.         } else {
  532.           string[iindex++] = ch;
  533.           Writechar(ch);
  534.           escaped = ( ch == '\\' ? ON : OFF);
  535.         }
  536.         }
  537.     } while (iindex < SLEN);
  538.  
  539.     string[iindex] = '\0';
  540.  
  541.     if (cursor_control)
  542.       transmit_functions(ON);
  543.     return(0);
  544. }
  545.  
  546. int
  547. GetPrompt()
  548. {
  549.     /** This routine does a read/timeout for a single character.
  550.         The way that this is determined is that the routine to
  551.         read a character is called, then the "errno" is checked
  552.         against EINTR (interrupted call).  If they match, this
  553.         returns NO_OP_COMMAND otherwise it returns the normal
  554.         command.  On BSD systems, the EINTR will never be returned
  555.         so we instead longjmp from the signal handler.
  556.     **/
  557.  
  558.     int ch;
  559.  
  560.     if (timeout > 0) {
  561.       alarm((unsigned) timeout);
  562. #ifdef    BSD
  563.       if (setjmp(GetPromptBuf)) {
  564.         InGetPrompt = 0;
  565.         ch = NO_OP_COMMAND;
  566.         alarm((unsigned) 0);
  567.       }
  568.       else {
  569.         InGetPrompt = 1;
  570.         ch = ReadCh();
  571.         InGetPrompt = 0;
  572.         alarm((unsigned) 0);
  573.       }
  574.     }
  575.     else
  576.       ch = ReadCh();
  577. #else
  578.         errno = 0;    /* we actually have to do this.  *sigh*  */
  579.         ch = ReadCh();
  580.         if (errno == EINTR) ch = NO_OP_COMMAND;
  581.         alarm((unsigned) 0);
  582.     }
  583.     else {
  584.       errno = 0;
  585.       ch = ReadCh();
  586.       if (errno == EINTR) ch = NO_OP_COMMAND;
  587.     }
  588. #endif
  589.  
  590.     return(ch);
  591. }
  592.  
  593.